package cn.avalon.user.interceptor;

import cn.avalon.basic.jwt.JwtUtils;
import cn.avalon.basic.jwt.LoginData;
import cn.avalon.basic.jwt.Payload;
import cn.avalon.basic.jwt.RsaUtils;
import cn.avalon.system.annotation.PreAuthorize;
import cn.avalon.system.mapper.PermissionMapper;
import cn.avalon.user.domain.Logininfo;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.security.PublicKey;
import java.util.List;

/**
 * @description: 登录拦截器
 * @author: Avalon
 * @date: 2022年08月27日 ： 15:30
 * @version: ver1.0
 * @email 709785494@qq.com
 */
@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Autowired
    private PermissionMapper permissionMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 判断有没有登录 -- redis信息是否为空
        String token = request.getHeader("token");
        if (token != null) {
            Logininfo logininfo = null;
            try {
                PublicKey publicKey = RsaUtils.getPublicKey(JwtUtils.class.getClassLoader().getResource("auth_rsa.pub").getFile());
                //解密之后获取载荷数据
                Payload<LoginData> payload = JwtUtils.getInfoFromToken(token, publicKey, LoginData.class);
                logininfo = payload.getLoginData().getLogininfo();
            } catch (ExpiredJwtException e) {
                response.setContentType("application/json;charset=UTF-8");
                PrintWriter writer = response.getWriter();
                writer.println("{\"success\":false,\"msg\":\"timeout\"}");
                return false;
            }
            // 刷新redis保存时间 目前刷新不了
            // redisTemplate.opsForValue().set(token,o,30, TimeUnit.MINUTES);

            // 如果登录为用户则直接放行
            if (logininfo.getType() == 1) {
                //1.如果是前端用户 user ，不需要校验任何权限，直接放行即可
                return true;//放行
            }
            //b.登录成功校验2 - 如果是后台用户 - 继续校验权限
            //b1.哪些请求需要校验权限 （答：打了自定义注解PreAuthorize权限的方法）
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            //b2.获取当前请求/接口/controller中方法上的权限信息 - 是否有自定义注解@PreAuthorize
            PreAuthorize preAuthorize = handlerMethod.getMethodAnnotation(PreAuthorize.class);
            //b3.如果preAuthorize为空：该方法中上没有加这个注解 - 说明公共资源不需要校验权限 - 放行
            if (preAuthorize == null) {
                //b31. 没有就放行,公共资源不需要校验权限
                return true;
            } else { //该方法中上加了这个注解 - 说明特殊资源需要校验权限
                //b32.有就校验是否有权限访问 - 获取注解上的value值
                String sn = preAuthorize.sn();
                //b33.查询出当前登录人所拥有的权限：t_permission表中的sn
                List<String> permissions  = permissionMapper.findPerssionSnByLogininfoId(logininfo.getId());
                //b34.如果集合中包含当前sn - 说明有权限访问 - 放行
                if (permissions .contains(sn)) {
                    return true;//终于有权限访问了
                }
                //b35.如果不包含：告诉他没有权限，请他去联系管理员
                response.setContentType("application/json;charset=utf-8");
                PrintWriter writer = response.getWriter();
                writer.print("{\"success\":false,\"message\":\"noPermission\"}");
                return false;
            }
        }

        // token == null，obj == null 都需要重新登录，跳转到登录界面
        //告诉浏览器我要给你响应一个json数据，用Utf-8编码
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println("{\"success\":false,\"msg\":\"noLogin\"}");
        return false;
    }
}
